import pyglet
from pyglet import gl
import Box2D2 as box2d

import numpy as np

import fast_shadow as fs

import dijkstra as dijkstra
from decodeSVG.decodeSVG import SVGParser
#from astar_map import *
##from test_main import *

from actuator import *
from decoration import *


import iceberg


class grBlended (pyglet.graphics.Group):
    """
    This pyglet rendering group enables blending.
    """
    def set_state(self):
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        
    def unset_state(self):
        gl.glDisable(gl.GL_BLEND)

class grPointSize (pyglet.graphics.Group):
    """
    This pyglet rendering group sets a specific point size.
    """
    def __init__(self, size=4.0):
        super(grPointSize, self).__init__()
        self.size = size
    def set_state(self):
        gl.glPointSize(self.size)
    def unset_state(self):
        gl.glPointSize(1.0)
        
        
class grText(pyglet.graphics.Group):
    """
    This pyglet rendering group sets the proper projection for
    displaying text when used.
    """
    window = None
    def __init__(self, window=None):
        super(grText, self).__init__()
        self.window = window

    def set_state(self):
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glPushMatrix()
        gl.glLoadIdentity()
        gl.gluOrtho2D(0, self.window.width, 0, self.window.height)

        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glPushMatrix()
        gl.glLoadIdentity()

    def unset_state(self):
        gl.glPopMatrix()
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glPopMatrix()
        gl.glMatrixMode(gl.GL_MODELVIEW)

class fwDebugDraw(box2d.b2DebugDraw):
    """
    This debug draw class accepts callbacks from Box2D (which specifies what to draw)
    and handles all of the rendering.

    If you are writing your own game, you likely will not want to use debug drawing.
    Debug drawing, as its name implies, is for debugging.
    """
    blended = grBlended()
    circle_segments = 16
    surface = None
    circle_cache_tf = {} # triangle fan (inside)
    circle_cache_ll = {} # line loop (border)
    def __init__(self): super(fwDebugDraw, self).__init__()
    def triangle_fan(self, vertices):
        """
        in: vertices arranged for gl_triangle_fan ((x,y),(x,y)...)
        out: vertices arranged for gl_triangles (x,y,x,y,x,y...)
        """
        out = []
        for i in range(1, len(vertices)-1):
            # 0,1,2   0,2,3  0,3,4 ..
            out.extend( vertices[0  ] )
            out.extend( vertices[i  ] )
            out.extend( vertices[i+1] )
        return len(out) / 2, out

    def line_loop(self, vertices):
        """
        in: vertices arranged for gl_line_loop ((x,y),(x,y)...)
        out: vertices arranged for gl_lines (x,y,x,y,x,y...)
        """
        out = []
        for i in range(0, len(vertices)-1):
            # 0,1  1,2  2,3 ... len-1,len  len,0
            out.extend( vertices[i  ] )
            out.extend( vertices[i+1] )
        
        out.extend( vertices[len(vertices)-1] )
        out.extend( vertices[0] )

        return len(out)/2, out

    def _getLLCircleVertices(self, radius, points):
        """
        Get the line loop-style vertices for a given circle.
        Drawn as lines.

        "Line Loop" is used as that's how the C++ code draws the
        vertices, with lines going around the circumference of the
        circle (GL_LINE_LOOP).

        This returns 'points' amount of lines approximating the 
        border of a circle.

        (x1, y1, x2, y2, x3, y3, ...)
        """
        ret = []
        step = 2*math.pi/points
        n = 0
        for i in range(0, points):
            ret.append( (math.cos(n) * radius, math.sin(n) * radius ) )
            n += step
            ret.append( (math.cos(n) * radius, math.sin(n) * radius ) )
        return ret

    def _getTFCircleVertices(self, radius, points):
        """
        Get the triangle fan-style vertices for a given circle.
        Drawn as triangles.

        "Triangle Fan" is used as that's how the C++ code draws the
        vertices, with triangles originating at the center of the
        circle, extending around to approximate a filled circle
        (GL_TRIANGLE_FAN).

        This returns 'points' amount of lines approximating the 
        circle.

        (a1, b1, c1, a2, b2, c2, ...)
        """
        ret = []
        step = 2*math.pi/points
        n = 0
        for i in range(0, points):
            ret.append( (0.0, 0.0) )
            ret.append( (math.cos(n) * radius, math.sin(n) * radius ) )
            n += step
            ret.append( (math.cos(n) * radius, math.sin(n) * radius ) )
        return ret

    def getCircleVertices(self, center, radius, points):
        """
        Returns the triangles that approximate the circle and
        the lines that border the circles edges, given
        (center, radius, points).

        Caches the calculated LL/TF vertices, but recalculates
        based on the center passed in.

        TODO: As of this point, there's only one point amount,
        so the circle cache ignores it when storing. Could cause 
        some confusion if you're using multiple point counts as
        only the first stored point-count for that radius will
        show up.

        Returns: (tf_vertices, ll_vertices)
        """
        if radius not in self.circle_cache_tf.keys():
            self.circle_cache_tf[radius]=self._getTFCircleVertices(radius,points)
            self.circle_cache_ll[radius]=self._getLLCircleVertices(radius,points)

        ret_tf, ret_ll = [], []

        for x, y in self.circle_cache_tf[radius]:
            ret_tf.extend( (x+center.x, y+center.y) )
        for x, y in self.circle_cache_ll[radius]:
            ret_ll.extend( (x+center.x, y+center.y) )
        return ret_tf, ret_ll

    def DrawCircle(self, center, radius, color):
        """
        Draw an unfilled circle given center, radius and color.
        """
        unused, ll_vertices = self.getCircleVertices( center, radius, self.circle_segments)
        ll_count = len(ll_vertices)/2

        self.batch.add(ll_count, gl.GL_LINES, None,
            ('v2f', ll_vertices),
            ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count)))

    def DrawSolidCircle(self, center, radius, axis, color):
        """
        Draw an filled circle given center, radius, axis (of orientation) and color.
        """
        tf_vertices, ll_vertices = self.getCircleVertices( center, radius, self.circle_segments)
        tf_count, ll_count = len(tf_vertices) / 2, len(ll_vertices) / 2


        self.batch.add(tf_count, gl.GL_TRIANGLES, self.blended,
            ('v2f', tf_vertices),
            ('c4f', [0.5 * color.r, 0.5 * color.g, 0.5 * color.b, 0.5] * (tf_count)))

        self.batch.add(ll_count, gl.GL_LINES, None,
            ('v2f', ll_vertices),
            ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count)))

        p = center + radius * axis
        self.batch.add(2, gl.GL_LINES, None,
            ('v2f', (center.x, center.y, p.x, p.y)),
            ('c3f', [1.0, 0.0, 0.0] * 2))

    def DrawPolygon(self, vertices, vertexCount, color):
        """
        Draw a wireframe polygon given the world vertices (tuples) with the specified color.
        """
        ll_count, ll_vertices = self.line_loop(vertices)

        self.batch.add(ll_count, gl.GL_LINES, None,
            ('v2f', ll_vertices),
            ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count)))

    def DrawSolidPolygon(self, vertices, vertexCount, color):
        """
        Draw a wireframe polygon given the world vertices (tuples) with the specified color.
        """
        tf_count, tf_vertices = self.triangle_fan(vertices)

        self.batch.add(tf_count, gl.GL_TRIANGLES, self.blended,
            ('v2f', tf_vertices),
            ('c4f', [0.5 * color.r, 0.5 * color.g, 0.5 * color.b, 0.5] * (tf_count)))

        ll_count, ll_vertices = self.line_loop(vertices)

        self.batch.add(ll_count, gl.GL_LINES, None,
            ('v2f', ll_vertices),
            ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count)))

    def DrawSegment(self, p1, p2, color):
        """
        Draw the line segment from p1-p2 with the specified color.
        """
        self.batch.add(2, gl.GL_LINES, None,
            ('v2f', (p1.x, p1.y, p2.x, p2.y)),
            ('c3f', [color.r, color.g, color.b]*2))

    def DrawXForm(self, xf):
        """
        Draw the transform xf on the screen
        """
        p1 = xf.position
        k_axisScale = 0.4
        p2 = p1 + k_axisScale * xf.R.col1
        p3 = p1 + k_axisScale * xf.R.col2

        self.batch.add(3, gl.GL_LINES, None,
            ('v2f', (p1.x, p1.y, p2.x, p2.y, p1.x, p1.y, p3.x, p3.y)),
            ('c3f', [1.0, 0.0, 0.0] * 2 + [0.0, 1.0, 0.0] * 2))

    def DrawPoint(self, p, size, color):
        """
        Draw a single point at point p given a point size and color.
        """
        self.batch.add(1, gl.GL_POINTS, grPointSize(size),
            ('v2f', (p.x, p.y)),
            ('c3f', [color.r, color.g, color.b]))
        
    def DrawAABB(self, aabb, color):
        """
        Draw a wireframe around the AABB with the given color.
        """
        self.debugDraw.batch.add(8, gl.GL_LINES, None,
            ('v2f', (aabb.lowerBound.x, aabb.lowerBound.y, abb.upperBound.x, aabb.lowerBound.y, 
                abb.upperBound.x, aabb.lowerBound.y, aabb.upperBound.x, aabb.upperBound.y,
                aabb.upperBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.upperBound.y,
                aabb.lowerBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.lowerBound.y)),
            ('c3f', [color.r, color.g, color.b] * 8))

    def DrawXForm(self, xf):
        """
        Draw the transform xf on the screen

        TODO: is this working?
        """
        p1 = xf.position
        k_axisScale = 0.4
        p2 = p1 + k_axisScale * xf.R.col1
        p3 = p1 + k_axisScale * xf.R.col2

        color = (1.0,0,0)
        self.DrawSegment(p1, p2, color)

        color = (0,1.0,0)
        self.DrawSegment(p1, p3, color)

class Component(object):
    
    desc="Generic component"
    def __init__(self,iParent,iPos,iAngle):
        self.parent=iParent
        self.pos=iPos
        self.angle=iAngle
        self.active=False
        self.ID=self.parent.VOID_COMPONENT_ID
        
    def draw(self,dt):
        pass
 
    def loop(self,dt):
        pass

class Bomb(Component):
    desc="bomb"
    def __init__(self,iParent,iPos,iRange,iStrength):
        super(Bomb,self).__init__(iParent,iPos,0.)
        self.ID=self.parent.BOMB_COMPONENT_ID
        self.range=iRange
        self.strength=iStrength
    
    def explode(self):
        neighbours=self.parent.parent.getVisibleNeighbours(self.parent,self.range)
        for n in neighbours:
            a,d,D=n
            f=self.strength*(1.0-(d/self.range)**2)
            a.applyDamage(f)
            norm=f*10.
            F=D*float(norm)
            p=a.getPosition(False)
            a.body.ApplyForce(F,p)
        self.parent.applyDamage(10000)
        

class Engine(Component):
    
    desc="Engine"
    def __init__(self,iParent,iPos,iPower,iMSpeed):
        super(Engine,self).__init__(iParent,iPos,0.)
        
        self.maxForce=iPower
        self.maxSpeed=iMSpeed
        self.active=True
        
        self.ID=self.parent.ENGINE_COMPONENT_ID
        
        self.turnRatio=0.3
        
        
        self.lightSize=1.0
        self.amplitude=0.5
        self.period=0.5
        self.actuator=SineActuator(0,-self.amplitude,self.period*0.5)
        
        self.texture=self.parent.parent.getTexture('red_light')
    
    def loop(self,dt):
        
        
        finished,val=self.actuator.val()
        if finished:
            self.actuator.restart(val,-val,self.period)
            
        self.lightSize=1.+val
          
    def move(self,iDir,iDist):
        
        #ensure the force is applied in the forward direction
        lf=self.parent.body.GetLocalVector(iDir)
        llf=lf.Length()
        
        if lf.y==0:
            ratio=self.turnRatio
        else :
            ratio=min(abs(lf.x/lf.y),self.turnRatio)
        
    
        lf.y=llf*(1-ratio)
        
        if lf.x<0 :
            lf.x=-llf*ratio
        else :
            lf.x=llf*ratio
        
            
        dist=self.parent.body.GetWorldVector(lf)

        p=self.parent.body.GetWorldPoint(box2d.b2Vec2(0.0,-1.0))
        v=self.parent.body.GetLinearVelocity()
        if v.Length()<self.maxSpeed:
            f=iDist*0.1
            f=(max(self.maxForce,f)*-1.0/iDist)*dist
            
            self.parent.body.ApplyForce(f,p)

    def draw(self,dt):
        
        lpos=self.parent.body.GetWorldPoint(box2d.b2Vec2(self.pos[0],self.pos[1]))
        x,y=pos=lpos.tuple()
        
        gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT | gl.GL_ENABLE_BIT)
        gl.glPushMatrix()
        gl.glTranslatef(x,y,0.)
        
        
        gl.glScalef(self.lightSize*0.05,self.lightSize*0.05,1.)
        gl.glEnable(gl.GL_BLEND)

        self.texture.blit(0,0)
        
        gl.glPopMatrix()
        gl.glPopAttrib()

class Tow(Component):
    
    desc="Tow"
    def __init__(self,iParent,iPos,iRange):
        super(Tow,self).__init__(iParent,iPos,0.)
        
        self.range=100
        self.active=True
        
        self.joint=None
        self.load=None
        self.tractorMaxRange=iRange
        self.ID=self.parent.TOW_COMPONENT_ID
        
        
    def attach(self,target):
        if self.load or self.joint:
            self.detach()
        
        if target:
            self.load=target
            D=self.parent.body.GetPosition()-target.body.GetPosition()
            d=D.Length()
            
            if d<=self.tractorMaxRange :
                print "target in Range"
                jointDef = box2d.b2DistanceJointDef()
                jointDef.Initialize(self.parent.body,
                    target.body,
                    self.parent.body.GetWorldPoint(box2d.b2Vec2(0.,1.)),
                    target.body.GetWorldPoint(box2d.b2Vec2(0.0,0.0)))
                jointDef.collideConnected = True
                self.joint = self.parent.world.CreateJoint(jointDef).getAsType()
                return True
                
            else :
                print "target out of Range"
                return False
    
    def detach(self):
        if self.load:
            self.load=None
        
        if self.joint:
            self.parent.world.DestroyJoint(self.joint)
            self.joint=None
        
        return True
    
    
class TractorBeam(Component):
    
    desc="TractorBeam"
    def __init__(self,iParent,iPos,iRange,iPower):
        super(TractorBeam,self).__init__(iParent,iPos,0.)
        
        self.range=iRange
        self.power=iPower
        self.maxForce=iPower*iRange*0.6
        self.active=True
        
        
        self.load=None
        
        self.ID=self.parent.TOW_COMPONENT_ID
        
        
    def attach(self,target):
        if self.load:
            self.detach()
        
        if target:
            self.load=target
            D=self.parent.body.GetPosition()-target.body.GetPosition()
            d=D.Length()
            
            if d<=self.range :
                print "target in Range"
                self.load=target
                return True
                
            else :
                print "target out of Range"
                return False
    
    def detach(self):
        if self.load:
            self.load=None
        
        
        return True
    
    def loop(self,dt):
        if self.load and self.active:
            D=self.parent.body.GetPosition()-self.load.body.GetPosition()
            d=D.Length()
            p=self.parent.body.GetWorldPoint(box2d.b2Vec2(0.0,1.5))
        
            if d>self.range :
                self.detach()
                return 
            f=(d-self.range/2)*self.power
            if abs(f)>self.maxForce:
                print "Too much stress !"
                self.detach()
                return
            
            F=-(f/d)*D
            
            
            self.parent.body.ApplyForce(F,p)
            p=self.load.body.GetWorldPoint(box2d.b2Vec2(0.0,1.0))
            self.load.body.ApplyForce(-F,p)
        


class Radar(Component):
    
    desc="Radar"
    
    def __init__(self,iParent,iPos,iAngle):
        super(Radar,self).__init__(iParent,iPos,iAngle)
        self.initTrigo(45)
        self.range=40
        self.active=True
        self.ID=self.parent.RADAR_COMPONENT_ID
        
        self.amplitude=45
        self.period=2
        self.actuator=SineActuator(0,-self.amplitude,self.period//2)
        self.orient=-45
        
        self.test=True

    def draw(self,dt):
        self.drawRadar()
    
    def loop(self,dt):
        self.orient=(self.parent.body.GetAngle()+self.angle)/self.degtorad
        self.orient-=90.
        
        finished,val=self.actuator.val()
        if finished:
            self.actuator.restart(val,-val,2)
            
        
        self.orient+=val
        
    def initTrigo(self,width):
        self.degtorad=3.141592/180.
        self.cos=[math.cos(i*self.degtorad) for i in range(360)]
        self.sin=[math.sin(i*self.degtorad) for i in range(360)]
        
        self.btRadarFan=pyglet.graphics.Batch()
        
        
        ptFan=[0.,0.]
        colFan=[0.,1.0,0.0,0.2]
        angle=-width
        subdiv=5
        radius=1.0
        n=1
        while angle<width:
            angle+=subdiv
            a=angle%360
            intens=(1.0*(width-abs(angle)))/width
            colFan.extend((0.,intens,0.,intens*0.5))
            ptFan.extend((radius*self.cos[a] ,radius*self.sin[a] ) )
            n+=1
            
        self.btRadarFan.add(n,pyglet.gl.GL_TRIANGLE_FAN, None,('v2f',ptFan),('c4f',colFan))
           
    
    def drawRadar(self):
        
        if not self.active:
            return
        lpos=self.parent.body.GetWorldPoint(box2d.b2Vec2(self.pos[0],self.pos[1]))
        x,y=pos=lpos.tuple()
        
        
        gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT | gl.GL_STENCIL_BUFFER_BIT | gl.GL_ENABLE_BIT)
    
        gl.glClearStencil(0)
        gl.glClear(gl.GL_STENCIL_BUFFER_BIT)

        ## step 1
        ## turning off writing to the color buffer and depth buffer so we only 
        ## write to stencil buffer
        gl.glColorMask(0,0,0,0)
        gl.glDepthMask(0)

        ## enable stencil buffer
        gl.glEnable(gl.GL_STENCIL_TEST)
        
        
        bShadow = pyglet.graphics.Batch()
    
        myCenter=self.parent.body.GetPosition()
        for ic in self.parent.parent.icebergs:
            if (ic.body.GetPosition()-myCenter).Length()<self.range*2:
                (ind,vert)=ic.ic.getShadowVerticesAndIndexes(pos,2*self.range)
                
                n=len(vert)//2
                bShadow.add_indexed(n,pyglet.gl.GL_TRIANGLES,None,ind,('v2f',vert),('c4b',[255]*(4*n)))

        
        for ac in self.parent.parent.actors:
            if not ac==self.parent and ac.body:
                (ind,vert)=ac.getShadowAbsVerticesIndices(pos,2*self.range)
                n=len(vert)//2
                bShadow.add_indexed(n,pyglet.gl.GL_TRIANGLES,None,ind,('v2f',vert),('c4b',[255]*(4*n)))

        

        ## write a one to the stencil buffer everywhere we are about to draw
        gl.glStencilFunc(gl.GL_ALWAYS, 1, 0xFFFFFFFF)
        ## this is to always pass a one to the stencil buffer where we draw
        gl.glStencilOp(gl.GL_REPLACE, gl.GL_REPLACE, gl.GL_REPLACE)

        ## render the plane which the shadow will be on
        ## color and depth buffer are disabled, only the stencil buffer
        ## will be modified
        color =  box2d.b2Color(1.0,1.0,1.0)
        
        bShadow.draw()
##        for ac in self.parent.parent.actors:
##            if not ac==self.parent and ac.body:
##                if (ac.getPosition(False)-myCenter).Length()<self.range:
##            
##                    ac.drawShadow(pos,2*self.range)
##                
        
        ## turn the color and depth buffers back on
        gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE)
        gl.glDepthMask(gl.GL_TRUE)


        ## until stencil test is diabled, only write to areas where the
        ## stencil buffer has a one. This is to draw the shadow only on
        ## the floor.
        gl.glStencilFunc(gl.GL_EQUAL, 0, 0xFFFFFFFF)

        ## don't modify the contents of the stencil buffer
        gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_KEEP)
        ## end step 1

        
        
        
        gl.glPushMatrix()
        gl.glTranslatef(x,y,0.)
        
        
        gl.glRotatef(self.orient,0.,0.,1.)
        gl.glScalef(self.range,self.range,1.)
        gl.glEnable(gl.GL_BLEND)

        self.btRadarFan.draw() 
        
        gl.glDisable(gl.GL_BLEND)   
        gl.glPopMatrix()
        gl.glDisable(gl.GL_STENCIL_TEST)
        gl.glPopAttrib()
        
        
class Sonar(Component):
    
    desc="Sonar"
    
    def __init__(self,iParent,iPos,iRange):
        super(Sonar,self).__init__(iParent,iPos,iRange)
        self.initSonar()
        self.range=iRange
        self.active=True
        self.ID=self.parent.RADAR_COMPONENT_ID
        
        self.amplitude=iRange*0.95
        self.period=2.
        self.actuator=Actuator(self.range-self.amplitude,self.amplitude,self.period)#InvSqrActuator(self.range-self.amplitude,self.amplitude,self.period)
        self.range2=self.range-self.amplitude

        self.test=False
        
    def draw(self,dt):
        self.drawSonar()
    
    def loop(self,dt):
        
        finished,val=self.actuator.val()
        if finished:
            self.actuator.restart(self.range-self.amplitude,self.range,self.period)
            
        
        self.range2=val
        
    def initSonar(self):
        self.degtorad=3.141592/180.
        self.cos=[math.cos(i*self.degtorad) for i in range(360)]
        self.sin=[math.sin(i*self.degtorad) for i in range(360)]
        
        self.btRadarFan=pyglet.graphics.Batch()
        
        
        ptFan=[0.,0.]
        colFan=[0.,1.0,0.0,0.5]
        angle=0
        subdiv=5
        radius=1.0
        n=1
        while angle<=360:
            angle+=subdiv
            a=angle%360
            intens=(1.0*(360-abs(angle)))/360.
            colFan.extend([0.,0.3,0.4,0.5])
            ptFan.extend((radius*self.cos[a] ,radius*self.sin[a] ) )
            n+=1
            
        self.btRadarFan.add(n,pyglet.gl.GL_TRIANGLE_FAN, None,('v2f',ptFan),('c4f',colFan))
        
        
        
           
    def drawSonar(self):
        
        if not self.active:
            return
        
        range=self.range2
        myCenter=self.parent.body.GetPosition()
        bShadow = pyglet.graphics.Batch()

        lpos=self.parent.body.GetWorldPoint(box2d.b2Vec2(self.pos[0],self.pos[1]))
        x,y=pos=lpos.tuple()
        
        for ic in self.parent.parent.icebergs:
            if (ic.getPosition(False)-myCenter).Length()<range*ic.radius:
                (ind,vert)=ic.ic.getShadowRelVertexIndices(pos,range,2.)
                n=len(vert)//2
                bShadow.add_indexed(n,pyglet.gl.GL_TRIANGLES,None,ind,('v2f',vert),('c4b',[0,220,255,127]*n))
        for ac in self.parent.parent.actors:
            if not ac==self.parent and ac.body:
                if (ac.getPosition(False)-myCenter).Length()<range+ac.radius:
                    (ind,vert)=ac.getShadowRelVertexIndices(pos,range,2.)
                    n=len(vert)//2
                    bShadow.add_indexed(n,pyglet.gl.GL_TRIANGLES,None,ind,('v2f',vert),('c4b',[127,127,255,127]*n))
             
        
        if self.test: self.test=False
        
        gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT | gl.GL_STENCIL_BUFFER_BIT | gl.GL_ENABLE_BIT)
    
       
        gl.glClearStencil(0)
        gl.glClear(gl.GL_STENCIL_BUFFER_BIT)

        ## step 1
        ## turning off writing to the color buffer and depth buffer so we only 
        ## write to stencil buffer
        gl.glColorMask(0,0,0,0)
        gl.glDepthMask(0)

        ## enable stencil buffer
        gl.glEnable(gl.GL_STENCIL_TEST)
        
         

        ## this is to always pass a one to the stencil buffer where we draw
        gl.glStencilOp(gl.GL_REPLACE, gl.GL_REPLACE, gl.GL_REPLACE)

        gl.glPushMatrix()
        gl.glTranslatef(x,y,0.)
        
        
        fact=0.98
        
        f_inv=1/fact
        r2=range*(f_inv)
        
        ## draw the exterior circle
        gl.glScalef(r2,r2,1.)
        gl.glStencilFunc(gl.GL_ALWAYS, 1, 0xFFFFFFFF)
        self.btRadarFan.draw() 

        ##empty the interior
        gl.glScalef(fact,fact,1.)
        
        gl.glStencilFunc(gl.GL_ALWAYS, 0, 0xFFFFFFFF)
        self.btRadarFan.draw() 
        
        #draw the inner rim of the shadow        
        gl.glStencilFunc(gl.GL_ALWAYS, 1, 0xFFFFFFFF)
        bShadow.draw()
        
        #empty the inetrior of the shadow
        gl.glScalef(f_inv,f_inv,1.)

        gl.glStencilFunc(gl.GL_ALWAYS, 0, 0xFFFFFFFF)
        
        bShadow.draw()
            
        
        ## turn the color and depth buffers back on
        gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE)
        gl.glDepthMask(gl.GL_TRUE)


        ## until stencil test is diabled, only write to areas where the
        ## stencil buffer has a 1 This is to draw the shadow only on
        ## the floor.
        gl.glStencilFunc(gl.GL_EQUAL, 1, 0xFFFFFFFF)

        ## don't modify the contents of the stencil buffer
        gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_KEEP)
        ## end step 1

        gl.glEnable(gl.GL_BLEND)

        self.btRadarFan.draw() 
        
          
        gl.glPopMatrix()
        
        gl.glDisable(gl.GL_STENCIL_TEST)
        gl.glPopAttrib()

    
       
class BaseObject(object):
    ACTION_NONE=0
    
    AM_WAIT=0
    
    def __init__(self,iParent,iName,iPos):
        self.name=iName

        
        self.isSelectable=True
        self.selected=False
        
        self.parent=iParent
        self.name=iName
        self.pos=iPos
        
        self.body=None
        
        self.actionQueue=[]
        self.currentAction=self.ACTION_NONE

        self.behaviourQueue=[]
        self.currentBehaviour=None
        
        self.actionTypeList={}
        self.actionSubList={}
        self.actionKeyList={}
        
        self.actionMode=self.AM_WAIT
        self.defaultActionMode=self.AM_WAIT
        
        self.actionTypeList[self.AM_WAIT]=self.ACTION_NONE
        self.actionSubList[self.ACTION_NONE]=self.defaultAction
        
        # Damage inflicted to other in case of collision
        self.extraDamage=0
        self.isDead=False
    
    def getPosition(self,asTuple=True):
        if asTuple:
            return self.pos.tuple()
        return self.pos
    
   
    def doKeyEvent(self,key):
        
        if key==pyglet.window.key.I:
            self.printInfo()
            return
        
        if key:
            if self.actionKeyList.has_key(key):
                self.actionMode=self.actionKeyList[key]
                print self.name+" : action set to "+str(self.actionMode)
        
        
    def dispose(self):
        print "%s : Bye Bye cruel world!"%(self.name)
        self.setIdle()
                
    def printInfo(self):
        print
        print "*********-*********"
        print "Information on BaseObject "+self.name
        
    def draw(self,dt):
        pass
    def drawComponents (self,dt):   
        pass
        
    def step(self,dt):
        """ Due to replace update()"""
        
        
        if self.currentBehaviour:
            if not self.currentBehaviour.finished:
                self.currentBehaviour.loop(dt)
            else :
                self.currentBehaviour=None
        if not self.currentBehaviour:
            if len(self.behaviourQueue)>0:
                self.currentBehaviour=self.behaviourQueue.pop(0)
                self.currentBehaviour.start(True)
        
        
    def setIdle(self):
        
        self.currentAction=self.ACTION_NONE
        self.currentBehaviour=None
        self.behaviourQueue[:]=[]
        
     
    def doAction(self,data):
        """ Called when user or robot action is triggered.
        Adds to the actionQueue the action corresponding
        to the current action mode AM_xxx
        if ctlr is pressed, clears the actionQueue before
        """
        actionType=self.actionTypeList[self.actionMode]
        self.actionSubList[actionType](data)
        
        self.actionMode=self.defaultActionMode
        
            
    def setSelected(self,value):
        if value:
            self.actionMode=self.defaultActionMode
        self.selected=value

    def defaultAction(self,data):
        pass
    
    def applyDamage(self,damage):
        self.HP-=damage
        if self.HP<0:
            self.isDead=True    


    
   
    
class Beacon(BaseObject):
    
    desc="Beacon"
    def __init__(self,iParent,iName,iPos):
        super(Beacon,self).__init__(iParent,iName,iPos)
        self.neighbours={}
        self.lightSize=1.0
        self.amplitude=0.5
        self.period=0.5
        self.actuator=SineActuator(0,-self.amplitude,self.period*0.5)
        
        self.texture=self.parent.getTexture('red_light')
        self.texture2=self.parent.getTexture('violet_light')
        
        
    def draw(self,dt):
        x,y=pos=self.pos.tuple()
        
        np=len(self.neighbours)*2
        if np>0:
            bLine=pyglet.graphics.Batch()
            points=[]
            

            for n in self.neighbours:
                points.extend(pos)
                points.extend(n.getPosition(True))
                
            bLine.add(np,gl.GL_LINES,None,('v2f',points),('c4f',[0.8,0.0,0.5,0.5]*np))
            gl.glPushAttrib(gl.GL_LINE_STIPPLE|gl.GL_BLEND|gl.GL_COLOR_BUFFER_BIT)
            gl.glEnable(gl.GL_LINE_STIPPLE)
            gl.glLineWidth(1)
            gl.glEnable(gl.GL_BLEND)
            gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        
            gl.glLineStipple(3,0xAFAF)
            bLine.draw()
            gl.glPopAttrib()
        
        finished,val=self.actuator.val()
        if finished:
            self.actuator.restart(val,-val,self.period)
            
        self.lightSize=1.+val
        
       
        
        gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT | gl.GL_ENABLE_BIT)
        gl.glPushMatrix()
        gl.glTranslatef(x,y,0.)
        
        
        gl.glScalef(self.lightSize*0.05,self.lightSize*0.05,1.)
        gl.glEnable(gl.GL_BLEND)
        if self.selected:
            self.texture.blit(0,0)
        else:
            self.texture2.blit(0,0)
        
        gl.glPopMatrix()
        gl.glPopAttrib()
        
        

    def attach(self,B,distance):
        if not B :
            return
        if not self.neighbours.has_key(B):
            if B.desc==self.desc:
                if distance<0:
                    D=B.pos-self.pos
                    distance=D.Length()
                    self.neighbours[B]=distance
                    B.attach(self,distance)
                    print "%s attached to %s"%(self.name,B.name)
                else : 
                    self.neighbours[B]=distance
                    print "%s attached to %s in return "%(self.name,B.name)
                    
        
        else: 
            self.detach(B)                
    
    def detach(self,B):
        if self.neighbours.has_key(B):
            del self.neighbours[B]
            B.detach(self)        
        
    def defaultAction(self,data):
        if data.has_key("Target"):
            p=data['Target']
            self.attach(p,-1)
        
class BaseActor(BaseObject):
    STATUS_ACTION_IDLE=0
    STATUS_ATTACH=2
    STATUS_TRACTOR=4
    
    ACTION_NONE=0
    ACTION_MOVE=1
    ACTION_ATTACH=2
    ACTION_DETACH=3
    ACTION_FETCH=5
    
    AM_ATTACH=1
    AM_DETACH=2
    AM_MOVE=3
    AM_FETCH=4
    
    
    
    desc="Base Actor"
    VOID_COMPONENT_ID=0
    TOW_COMPONENT_ID=1
    RADAR_COMPONENT_ID=2
    ENGINE_COMPONENT_ID=4
    BOMB_COMPONENT_ID=8
    
    def __init__(self,iParent,iName,iPos,iContour,iIcons):
        
        super(BaseActor,self).__init__(iParent,iName,iPos)
        self.body=None
        
        self.texActivated=iIcons[0].get_texture()
        self.texDeActivated=iIcons[1].get_texture()
        
        #self.texHealthBar=iIcons[2].get_texture()
##        self.texComponent=[]
##        for i in range(3,6):
##            self.texComponent.append(iIcons[i].get_texture())
##            
        self.initialHP=self.HP=100
        
        
        
        #self.worldMap=iMap
        
        self.world=iParent.world
        self.destination=None
        
        self.target=None
        self.destination=None
        
        self.maxSpeed=100.0
        self.maxAcc=80.0
        
        
        #list of components attached to this actor
        self.components={}
        
        if not iContour :
            self.points=self.parent.actorContour
        else :
            self.points=iContour

        self.initSilhouette(self.points)
        
        
        
        radius=0.
        ## radius calculation
        for pt in self.points:
            x,y=pt
            r=(x*x+y*y)
            if r>radius:
                radius=r
        self.radius=math.sqrt(radius)
        #print iName+" radius= "+str(self.radius)
        shapeDefs=self.initShapesDefs(self.points)
        self.initBody(iPos,shapeDefs)
        #self.initShadowElements(contour)
        
       
        #****
        
        self.contactList={}

        self.decorations=pyglet.app.WeakSet()

        self.actionKeyList[pyglet.window.key.M]=self.AM_MOVE
        self.actionTypeList[self.AM_MOVE]=self.ACTION_MOVE
        self.actionSubList[self.ACTION_MOVE]=self.moveAction
        
        self.actionKeyList[pyglet.window.key.A]=self.AM_ATTACH
        self.actionTypeList[self.AM_ATTACH]=self.ACTION_ATTACH
        self.actionSubList[self.ACTION_ATTACH]=self.attachAction
        
        self.actionKeyList[pyglet.window.key.D]=self.AM_DETACH
        self.actionTypeList[self.AM_DETACH]=self.ACTION_DETACH
        self.actionSubList[self.ACTION_DETACH]=self.detachAction
        
        self.actionKeyList[pyglet.window.key.F]=self.AM_FETCH
        self.actionTypeList[self.AM_FETCH]=self.ACTION_FETCH
        self.actionSubList[self.ACTION_FETCH]=self.fetchAction
       
        self.actionMode=self.AM_MOVE
        self.defaultActionMode=self.AM_MOVE
        
    
    
    def dispose(self):
        self.parent.world.DestroyBody(self.body)
     
    def getComponentByID(self,id):
        if self.components.has_key(id):
            return self.components[id]
        return None
    
    def visibilityCheck(self,other,range):
        """ Checks if another base actor is visible and in range
        Returns None if not visible or out of range,
        a tuple of actor,distance and diferential vector otherwise"""
        if other==self:
            return None
        segment=box2d.b2Segment()
        origin=self.getPosition(False)
        dest=other.getPosition(False)
        D=dest-origin
        d=D.Length()
        if d<=range: 
            segment.p2=dest
            segment.p1=origin+(dest-origin)*self.radius/d
            lambda_, normal, shape = self.parent.world.RaycastOne(segment,False,None)
            if shape.GetBody().GetUserData()==other:
                return (other,d,D)
        return None
    
         
                
    def printInfo(self):
        print
        print "*********-*********"
        print "Information on actor "+self.name
        print "Health : %d/%d"%(self.HP,self.initialHP)
        am=["None","Attach","Detach","Move"]
        print "Action mode "+am[self.actionMode]
        am=["None","Move","Attach","Detach"]        
        if self.currentBehaviour:
            print "Behaviour : %s"%(self.currentBehaviour.desc)
        else :
            print "Currently idle"
        if self.target:
            print "Target "+self.target.name
            D=self.body.GetPosition()-self.target.body.GetPosition()
            d=D.Length()
            print " Distance to target : "+str(d)
        else:
            print "No target..."
        
    def getPosition(self,asTuple):
        if asTuple:
            return self.body.GetPosition().tuple()
        return self.body.GetPosition()
    
    
    def initShapesDefs(self,contour):
        shapes=[]
        if contour: 
            
            contourDef = box2d.b2PolygonDef()
            
            contourDef.setVertices_tuple(contour)
            contourDef.density = 2.0
            shapes.append(contourDef)
        else:
            xf1 = box2d.b2XForm ()
            xf1.R.Set(0.3524 * box2d.b2_pi)
            xf1.position = box2d.b2Mul(xf1.R, box2d.b2Vec2(1.0, 0.0))

            sd1=box2d.b2PolygonDef() 
            sd1.vertexCount = 3
            sd1.setVertex(0, box2d.b2Mul(xf1, box2d.b2Vec2(-1.0, 0.0)))
            sd1.setVertex(1, box2d.b2Mul(xf1, box2d.b2Vec2(1.0, 0.0)))
            sd1.setVertex(2, box2d.b2Mul(xf1, box2d.b2Vec2(0.0, 0.5)))
            sd1.density = 2.0
            shapes.append(sd1)
            
            xf2 = box2d.b2XForm ()
            xf2.R.Set(-0.3524 * box2d.b2_pi)
            xf2.position = box2d.b2Mul(xf2.R, box2d.b2Vec2(-1.0, 0.0))

            sd2=box2d.b2PolygonDef() 
            sd2.vertexCount = 3
            sd2.setVertex(0, box2d.b2Mul(xf2, box2d.b2Vec2(-1.0, 0.0)))
            sd2.setVertex(1, box2d.b2Mul(xf2, box2d.b2Vec2(1.0, 0.0)))
            sd2.setVertex(2, box2d.b2Mul(xf2, box2d.b2Vec2(0.0, 0.5)))
            sd2.density = 2.0
            shapes.append(sd2)
        
        return shapes

    def initBody(self,iPos,shapeDefs):
        bd=box2d.b2BodyDef() 
        bd.angularDamping = 30.0
        bd.linearDamping = 4.0

        bd.userData=self
        bd.position.Set(iPos.x,iPos.y)
        bd.angle = box2d.b2_pi
        self.body = self.world.CreateBody(bd)
        for sd in shapeDefs:
            
            self.body.CreateShape(sd)
        
        print "SetMass"
        self.body.SetMassFromShapes()
        

    def step(self,dt):
        """ Due to replace update()"""
        
        for co in self.components.values():
            co.loop(dt)
                
        
        super(BaseActor,self).step(dt)
        
        for d in self.decorations:
            d.step(dt)
                
            
    def draw(self,dt):
            
        if self.currentBehaviour:
            self.currentBehaviour.draw()
            
            
        x,y=self.body.GetPosition().tuple()
        gl.glPushMatrix()
        gl.glTranslatef(x,y,0.)
        gl.glScalef(0.05,0.05,1.)
        
        gl.glEnable(gl.GL_BLEND)

        
        
        if self.selected:
            self.texActivated.blit(0,0)
        else:
            self.texDeActivated.blit(0,0)
            
##            pos=self.body.GetPosition()+box2d.b2Vec2(1.5,1.5)
##           
##            x,y=self.parent.ConvertWorldToScreen(pos)
##            self.parent.DrawString(x,y,self.name)
##        if self.components.has_key(BaseActor.TOW_COMPONENT_ID):
##            self.texComponent[2].blit(0,0)
##        if self.components.has_key(BaseActor.RADAR_COMPONENT_ID):
##            self.texComponent[1].blit(0,0)
##        if self.components.has_key(BaseActor.ENGINE_COMPONENT_ID):
##            self.texComponent[0].blit(0,0)
        gl.glPopMatrix() 
    
        
    
    def drawComponents (self,dt):   
        if len(self.components)>0:
            for c in self.components.values():
                c.draw(dt)    
        
        for d in self.decorations:
            d.draw()   
    
    def addContact(self, iName,iShape):
        if not self.contactList.has_key(iName):
            print iName+" added for "+str(iShape)
            self.contactList[iName]=iShape

    def removeContact(self, iName):
        if self.contactList.has_key(iName):
            print iName+" removed"
            self.contactList.pop(iName)
    

    ### Part dedicated to projected stencil shadow calculations 
    def getShadowRelVertexIndices(self,origin,range,shadowSize):
        fs.fast_shadow_rel(self.silhouette,self.vertices,self.getPosition(True),0.,origin,range,shadowSize)
        return (self.indices,self.vertices)
    
    def getShadowAbsVerticesIndices(self,origin,distance):
        fs.fast_shadow_abs(self.silhouette,self.vertices,self.getPosition(True),0.,origin,distance)
##        self.vertex_list.vertices=self.vertices
        
        return (self.indices,self.vertices)

##    def getShadowRelVertexIndices(self,origin,range,shadowSize):
##        contour=[]
##        sh=[]
##        vl=[]
##        self.updateSilhouette()
##        for p in self.worldContour:
##            contour.append([(a-b)/range for a,b in zip(p,origin)])
##        
##        for p in contour:
##            vl.extend(p)
##            sh.extend(self.extrude2D((0,0),p,shadowSize))
##        
##        vl.extend(sh)    
##        
##        return (self.shadowIndices,vl)
    
    def _drawShadow(self,origin,distance):
        self.updateSilhouette()        
        self.updateShadow(origin,distance)
        
        x,y=self.body.GetPosition().tuple()
        #orient=(self.body.GetAngle())*57.2958-90.
       
        gl.glPushMatrix()
        #gl.glLoadIdentity()
        #gl.glTranslatef(x,y,0.)
        
        #gl.glRotatef(orient,0.,0.,1.)

         
        
        
        self.shadowVertexList.draw(pyglet.gl.GL_TRIANGLES)
        gl.glPopMatrix()
        
##    def getShadowVerticesAndIndexes(self,origin,distance):
##        self.updateSilhouette()        
##        self.updateShadow(origin,distance)
##        v=self.shadowVertexList.vertices
##        i=self.shadowIndices
##        return (i,v)
    
       
    def _initShadowElements(self,iPoints):
        
        self.initSilhouette(iPoints)
        self.shadowVertexList=pyglet.graphics.vertex_list_indexed(self.nP*2
            ,self.shadowIndices,'v2f/stream',('c3B/static', [255]*(self.nP*6)))
                
        
        
        
        self.updateShadow((0.,0.),100.0)
       
    
    def _updateSilhouette(self):
        self.silhouette[:]=[]
        self.worldContour=[]
##        pos=self.body.GetPosition().tuple()
##        for i in range(self.nP):
##            rel=[a+b for a,b in zip(self.relSil[i],pos)]
##            self.silhouette.extend(rel)
        for i in range(self.nP):
            lPt=box2d.b2Vec2(self.relSil[i][0],self.relSil[i][1])
            lPT2=self.body.GetWorldPoint(lPt).tuple()
            self.worldContour.append(lPT2)
            self.silhouette.extend(lPT2)
        
           
    def _updateShadow(self,origin,distance):
        
        vl=[]
        vl[:]=self.silhouette
        sh=self.extrudeSilhouette(origin,distance)
        vl.extend(sh)
        self.shadowVertexList.vertices=vl
       
        
    def _extrude2D(self,o,p,d):
        xo,yo=o
        xp,yp=p
        dx=xp-xo
        dy=yp-yo
        d2=math.sqrt(dx**2+dy**2)
        if d2==0:
            return o
        f=d/d2
        if f<1 : f=1

        x=xo+dx*f
        y=yo+dy*f
        return (x,y)   
        
        
    
    def initSilhouette(self,iPoints):    
        nP=self.nP=len(iPoints)
        
        indices=[]
        for i in range(nP-1):
            indices.extend((i,i+nP,i+1))
            indices.extend((i,i+nP+1,i+1))
            indices.extend((i,i+nP,i+nP+1))
        indices.extend((nP-1,2*nP-1,0))
        indices.extend((nP-1,0,nP))
        indices.extend((nP-1,2*nP-2,2*nP-1))

##        for i in range(nP):
##            rel=[a-b for a,b in zip(iPoints[i],self.center)]
##            pos.extend(rel)
##            
        
        self.indices=indices
        self.silhouette=np.array(iPoints,float).ravel()
        
        self.shadowVertexList=pyglet.graphics.vertex_list_indexed(self.nP*2
            ,self.indices,'v2f/stream',('c3B/static', [255]*(self.nP*6)))
        
        self.vertices=np.zeros(nP*4,float)
        self.shadowVertexList.vertices=self.vertices
        #self.contour=np.array(iPoints).ravel()    
    
    def _initSilhouette(self,iPoints):
        """initializes the contour of the actor based on a serie of (x,y)
        """
        nP=self.nP=len(iPoints)+1
        self.silhouette=[]
        self.relSil=[]
        # relative coordinates
        self.relSil[:]=iPoints
        self.relSil.append(iPoints[0])
        indices=[]
        for i in range(nP-1):
            indices.extend((i,i+nP,i+1))
            indices.extend((i,i+nP+1,i+1))
            indices.extend((i,i+nP,i+nP+1))
        indices.extend((nP-1,2*nP-1,0))
        indices.extend((nP-1,0,nP))
        indices.extend((nP-1,2*nP-2,2*nP-1))

        self.shadowIndices=indices
        self.updateSilhouette()
        # indices for indexed polygon
        
        
    def _extrudeSilhouette(self, origin, distance):
        pos=[]
        
        for p in self.worldContour:
            pos.extend(self.extrude2D(origin,p,distance))
            
        return pos
    
    def applyDamage(self,damage):
        print "%s is suffering damage %s"%(self.name,str(damage))
        super(BaseActor,self).applyDamage(damage)
        self.decorations.add(DamageText(self,(1.,2.),str(damage)))

    ##
    ## Generic action, only activated if the corresponding component is installed
    ##
    
    def fetchAction(self,data):
        
        if not data:
            print "No data"
            return 
        
        self.behaviourQueue.append(FetchBehaviour(self,data))
        
    def moveAction(self,data):
        
    
        modifiers=data['Modifiers']
        data['Position']=(data['Position'],)
        if modifiers & pyglet.window.key.MOD_SHIFT:
            self.setIdle()
        if modifiers & pyglet.window.key.MOD_CTRL:
            dest=data['Position'][-1]
            #print "dest : "
            #print dest
            path=self.parent.computePath(self.getPosition(False),dest)
            path2=[]
            if path :
                for pt in path:
                    print pt
                    path2.append(pt)
            #path2.append(dest)
            data['Position']=path2  
        
        self.behaviourQueue.append(MoveBehaviour(self,data))
        

              
    def attachAction(self,data):
        
        self.behaviourQueue.append(AttachBehaviour(self,data))

    
    def detachAction(self):
        
        cp=self.getComponentByID(self.TOW_COMPONENT_ID)
        if cp:
            cp.detach()
 
    def explode(self):
        cp=self.getComponentByID(self.BOMB_COMPONENT_ID)
        if cp:
            cp.explode()
    

        
class HomeBase(BaseActor):
    desc="Home Base"
    def __init__(self,iParent,iName,iPos,iContour,iTex):
        super(HomeBase,self).__init__(iParent,iName,iPos,iContour,iTex)
        self.lpTex=self.parent.getTexture("launchpad")
        self.lpTexSel=self.parent.getTexture("launchpad_selected")
        
        self.lpPos=(0.,(self.lpTex.height+self.texActivated.height)//2)
        
    def draw(self,dt):
            
        if self.currentBehaviour:
            self.currentBehaviour.draw()
            
            
        x,y=self.body.GetPosition().tuple()
        gl.glPushMatrix()
        gl.glTranslatef(x,y,0.)
        gl.glScalef(0.05,0.05,1.)
        
        gl.glEnable(gl.GL_BLEND)

        
        
        if self.selected:
            self.texActivated.blit(0,0)
            self.lpTexSel.blit(*self.lpPos)
        else:
            self.texDeActivated.blit(0,0)
            self.lpTex.blit(*self.lpPos)
        
        
        
##            pos=self.body.GetPosition()+box2d.b2Vec2(1.5,1.5)
##           
##            x,y=self.parent.ConvertWorldToScreen(pos)
##            self.parent.DrawString(x,y,self.name)
##        if self.components.has_key(BaseActor.TOW_COMPONENT_ID):
##            self.texComponent[2].blit(0,0)
##        if self.components.has_key(BaseActor.RADAR_COMPONENT_ID):
##            self.texComponent[1].blit(0,0)
##        if self.components.has_key(BaseActor.ENGINE_COMPONENT_ID):
##            self.texComponent[0].blit(0,0)
        gl.glPopMatrix() 
    
        
class BombActor(BaseActor):
    def __init__(self,iParent,iName,iPos,iMap,iIcons):
        
        super(BombActor,self).__init__(iParent,iName,iPos,iMap,iIcons)
        self.components[self.BOMB_COMPONENT_ID]=Bomb(self,(0,0),20.,50.)
        

    def doKeyEvent(self,key):
        
        
        if key==pyglet.window.key.SPACE:
            self.explode()
        
        super(BombActor,self).doKeyEvent(key)
         
   
##class RadarActor(BaseActor):
##    STATUS_RADAR_ON=8
##    STATUS_RADAR_OFF=16
##    
##    def __init__(self,iParent,iName,iPos,iMap,iIcons):
##        
##        super(RadarActor,self).__init__(iParent,iName,iPos,iMap,iIcons)
##
##        self.radarOn=True
##        self.initTrigo(45)
##        self.range=100
##        
##    def draw(self,dt):
##        self.drawRadar()
##    
##
##    
##        
## 
##    def initTrigo(self,width):
##        self.degtorad=3.141592/180.
##        self.cos=[math.cos(i*self.degtorad) for i in range(360)]
##        self.sin=[math.sin(i*self.degtorad) for i in range(360)]
##        
##        self.btRadarFan=pyglet.graphics.Batch()
##        
##        
##        ptFan=[0.,0.]
##        colFan=[0.,1.0,0.0,0.5]
##        angle=-width
##        subdiv=5
##        radius=1.0
##        n=1
##        while angle<width:
##            angle+=subdiv
##            a=angle%360
##            intens=(1.0*(width-abs(angle)))/width
##            colFan.extend((0.,intens,0.,intens*0.5))
##            ptFan.extend((radius*self.cos[a] ,radius*self.sin[a] ) )
##            n+=1
##            
##        print n
##        print len(ptFan)//2
##
##        self.btRadarFan.add(n,pyglet.gl.GL_TRIANGLE_FAN, None,('v2f',ptFan),('c4f',colFan))
##           
##    
##    def drawRadar(self):
##        
##        if not self.radarOn:
##            return
##        
##        x,y=pos=self.body.GetPosition().tuple()
##        
##        
##        gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT | gl.GL_STENCIL_BUFFER_BIT | gl.GL_ENABLE_BIT)
##    
##        gl.glClearStencil(0)
##        gl.glClear(gl.GL_STENCIL_BUFFER_BIT)
##
##        ## step 1
##        ## turning off writing to the color buffer and depth buffer so we only 
##        ## write to stencil buffer
##        gl.glColorMask(0,0,0,0)
##        gl.glDepthMask(0)
##
##        ## enable stencil buffer
##        gl.glEnable(gl.GL_STENCIL_TEST)
##        
##        
##        bShadow = pyglet.graphics.Batch()
##
##        for ic in self.parent.icebergs.values():
##            #ic.ic.draw(pos,2*range)
##            (ind,vert)=ic.ic.getShadowVerticesAndIndexes(pos,2*self.range)
##            n=len(vert)//2
##            bShadow.add_indexed(n,pyglet.gl.GL_TRIANGLES,None,ind,('v2f',vert),('c4b',[255]*(4*n)))
##
##        for ac in self.parent.actors.values():
##            if not ac==self:
##                (ind,vert)=ac.getShadowVerticesAndIndexes(pos,2*self.range)
##                n=len(vert)//2
##                bShadow.add_indexed(n,pyglet.gl.GL_TRIANGLES,None,ind,('v2f',vert),('c4b',[255]*(4*n)))
##
##        
##
##        ## write a one to the stencil buffer everywhere we are about to draw
##        gl.glStencilFunc(gl.GL_ALWAYS, 1, 0xFFFFFFFF)
##        ## this is to always pass a one to the stencil buffer where we draw
##        gl.glStencilOp(gl.GL_REPLACE, gl.GL_REPLACE, gl.GL_REPLACE)
##
##        ## render the plane which the shadow will be on
##        ## color and depth buffer are disabled, only the stencil buffer
##        ## will be modified
##        color =  box2d.b2Color(1.0,1.0,1.0)
##        
##        bShadow.draw()
##        
##        ## turn the color and depth buffers back on
##        gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE)
##        gl.glDepthMask(gl.GL_TRUE)
##
##
##        ## until stencil test is diabled, only write to areas where the
##        ## stencil buffer has a one. This is to draw the shadow only on
##        ## the floor.
##        gl.glStencilFunc(gl.GL_EQUAL, 0, 0xFFFFFFFF)
##
##        ## don't modify the contents of the stencil buffer
##        gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_KEEP)
##        ## end step 1
##
##        
##        
##        orient=self.body.GetAngle()/self.degtorad
##        orient-=90.
##        gl.glPushMatrix()
##        gl.glTranslatef(x,y,0.)
##        
##        
##        gl.glRotatef(orient,0.,0.,1.)
##        gl.glScalef(self.range,self.range,1.)
##        gl.glEnable(gl.GL_BLEND)
##
##        self.btRadarFan.draw() 
##        
##        gl.glDisable(gl.GL_BLEND)   
##        gl.glPopMatrix()
##        gl.glDisable(gl.GL_STENCIL_TEST)
##        gl.glPopAttrib()
##        
##        
##        
##    
##    def doKeyEvent(self,key):
##
##        if key==pyglet.window.key.R:
##            self.radarOn=not self.radarOn
##            return
##        
##        super(MovingActor,self).doKeyEvent(key)
##      
    

class MovingActor(BaseActor):
    
    
    desc="MovingActor"
    
    def __init__(self,iParent,iName,iPos,iMap,iIcons):
        
        
        super(MovingActor,self).__init__(iParent,iName,iPos,iMap,iIcons)

        
        
        self.components[self.RADAR_COMPONENT_ID]=Sonar(self,(0,0),30.)
        self.components[self.ENGINE_COMPONENT_ID]=Engine(self,(0.,-1.),100.,80.)
        
        
    
    def doKeyEvent(self,key):

        if key==pyglet.window.key.T:
            self.components[self.RADAR_COMPONENT_ID].test=True
            
            return
        
        if key==pyglet.window.key.S:
            self.setIdle()
            
            return
        
        super(MovingActor,self).doKeyEvent(key)
      
       

    def initBody(self,iPos,shapeDefs):
        bd=box2d.b2BodyDef() 
        bd.angularDamping = 12.0
        bd.linearDamping = 4.0

        bd.userData=self
        bd.position.Set(iPos.x,iPos.y)
        bd.angle = box2d.b2_pi
        self.body = self.world.CreateBody(bd)
        for sd in shapeDefs:
            self.body.CreateShape(sd)
        
        self.body.SetMassFromShapes()
        
    
##    def applyForce(self,dist,d):
##        
##        #ensure the force is applied in the forward direction
##        lf=self.body.GetLocalVector(dist)
##        if lf.y<0:
##            lf.y=-lf.y
##        dist=self.body.GetWorldVector(lf)
##
##        p=self.body.GetWorldPoint(box2d.b2Vec2(0.0,-2.0))
##        v=self.body.GetLinearVelocity()
##        if v.Length()<self.maxSpeed:
##            f=d*0.1
##            f=(max(self.maxAcc,f)*-1.0/d)*dist
##            
##            self.body.ApplyForce(f,p)
##
                    
##    def update(self):
##        
##        super(MovingActor,self).update()
##        
##        ## The moving part specific to this class and derived
##        if self.destination :
##            dist=self.body.GetPosition()-self.destination
##            d=dist.Length()
##            if d<1.:
##                self.destination=None
##            else :
##                self.applyForce(dist,d)    
##        
##        else :
##            if len(self.waypoints)>0:
##                self.destination=self.waypoints.pop(0)
##                    
##                    
##                    
##                    
           
##    def parseActionQueue(self):
##        
##        act=None
##        
##        if self.status==self.STATUS_ACTION_IDLE:
##            if len(self.actionQueue)<1 :return None
##            act=self.actionQueue.pop(0)
##        
##            
##        
##        return act
##                
 
class Transporter(MovingActor):
    
    
    
    desc="Transporter"
    def __init__(self,iParent,iName,iPos,iMap,iIcons):
        super(Transporter,self).__init__(iParent,iName,iPos,iMap,iIcons)
        
        self.components[self.TOW_COMPONENT_ID]=TractorBeam(self,(0,-2),10.,20.)
        self.components[self.RADAR_COMPONENT_ID]=Radar(self,(0,-1),0)
##        box2d.b2ContactListener.__init__(self)
##        self.tractorJoint=None
##        self.tractorMaxRange=5.
##        self.maxAcc=120.0
##        
         
    def doKeyEvent(self,key):
        
        if key==pyglet.window.key.T:
            self.components[self.RADAR_COMPONENT_ID].test=True
            
            return
        
        if key==pyglet.window.key.D:
            cp=self.getComponentByID(self.TOW_COMPONENT_ID)
            if cp:
                cp.detach()
        
            return
        
        super(Transporter,self).doKeyEvent(key)
    
           

class Behaviour(object):
    def __init__(self,parent,data):
        self.id=0
        self.desc="IDLE"
        
        self.data=data
        self.parent=parent
        self.result=None
        self.finished=False
        if not data:
            self.fail("No data")
            
        
    
    def fail(self, text):
        print "%s failed : %s"%(self.desc,text)
        self.finished=True
        self.result=False
    
    def start(self,result):
        if not result:
            print "Previous action failed"
            self.result=False
            self.finished=True    
       
    def loop(self,dt):
        pass
    
    def dispose(self):
        pass
        
    def draw(self):
        pass

class CompositeBehaviour(Behaviour):
    def __init__(self,parent,data):
        super(CompositeBehaviour,self).__init__(parent,data)
        self.subBehaviourChain=[]
        self.currentBehaviour=None
        self.result=True
        self.data=data
        
    def fail(self, text):
        print "%s failed : %s"%(self.desc,text)
        self.finished=True
        self.result=False
        
    def loop(self,dt):
        
        if self.currentBehaviour:
            if self.currentBehaviour.finished:
                self.result=self.currentBehaviour.result
                if not self.result:
                    self.fail("")
                
            else :
                self.currentBehaviour.loop(dt)
                return
                
        if len(self.subBehaviourChain)>0:
            self.currentBehaviour=self.subBehaviourChain.pop(0)
            print "%s switching to %s"%(self.parent.name,self.currentBehaviour.desc)
            self.currentBehaviour.start(self.result)
        else:
            self.finished=True    
            
class MoveBehaviour(Behaviour):
    def __init__(self,parent,data):
        
        super(MoveBehaviour,self).__init__(parent,data)
        self.desc="Move behaviour"
        self.waypoints=[]
        self.proximity=1.0
        if data.has_key('Distance'):
            self.proximity=data['Distance']*0.8
            
        
        
        
        self.destination=None
        self.target=data['Target']
        self.modifiers=data['Modifiers']
        if self.target:
            dest=[self.target.body.GetPosition(),]
        elif data['Position']:
            dest=data['Position']
            print dest
        else :
            self.fail("No destination nor target")
            return
        
        if self.modifiers & pyglet.window.key.MOD_SHIFT:
            shift=True
            
        else :
            shift=False
        if self.modifiers & pyglet.window.key.MOD_ALT:
            alt=True
        else :
            alt=False
        
        for pt in dest:
            self.addWayPoint(pt, shift, alt)
        self.parent.body.WakeUp()
        
        
    def loop(self,dt):
        if not self.destination==None :
            
            dist=self.parent.body.GetPosition()-self.destination
            d=dist.Length()
            
            if d<self.proximity:
                
                self.destination=None
            else :
                cp=self.parent.getComponentByID(BaseActor.ENGINE_COMPONENT_ID)
                if cp:
                    cp.move(dist,d)
                else :
                    self.finished=True
                    self.result=False
                    
        
        if not self.destination :
            if len(self.waypoints)>0:
                self.destination=self.waypoints.pop(0)
                print self.destination
            else :
                print "%s Finished"%(self.desc)
                self.finished=True
                self.result=True       
    
    def clearPath(self):
        
        self.waypoints[:]=[]
        
        self.destination=None    

    def addWayPoint(self, dest,  clear, useAStar):
            
        if clear :
            self.clearPath()
        
        
        # Check if is using a path finding algorythm
        if useAStar:
            pos=(self.parent.body.GetPosition().x,self.parent.body.GetPosition().y)
            
            lwp=self.parent.worldMap.compute2DPath(pos,(dest.x,dest.y))
            #self.worldMap.debugPath(lwp)
            # if no path can be found
            if not lwp:
                self.destination = None
        
            else:
                
                for v in lwp:
                    self.waypoints.append(box2d.b2Vec2(v[0],v[1]))

        else: # if not using path finding, just add the point.
            self.waypoints.append(dest)
    
    def draw(self):
        pass
##        color =  box2d.b2Color(0.0,1.0,0.0)
##        if self.destination:
##            self.parent.parent.debugDraw.DrawPoint(self.destination,5.0, color)
##        color =  box2d.b2Color(1.0,0.0,0.0)
##        lwp=self.waypoints
##       if len(lwp)>0:
##            for wp in lwp:
##                self.parent.parent.debugDraw.DrawPoint(wp,5.0, color)
    

class FetchBehaviour(CompositeBehaviour):
    def __init__(self,iParent,iData):
        super(FetchBehaviour,self).__init__(iParent,iData)
        
        
        self.desc="Fetch behaviour"
        
        if not self.data['Target']:
            self.fail("No target")
            return
        initPos=box2d.b2Vec2(self.parent.body.GetPosition().x,self.parent.body.GetPosition().y)
        
        self.destination=iData['Position']
        self.target=iData['Target']
        self.modifiers=iData['Modifiers']
        self.data['Distance']=5.
        
        self.subBehaviourChain.append(MoveBehaviour(self.parent,self.data))
        self.subBehaviourChain.append(AttachBehaviour(self.parent,self.data))
        
        iData={}
        iData['Target']=None
        iData['Position']=[initPos,]
        iData['Modifiers']=self.modifiers
        
        
        self.subBehaviourChain.append(MoveBehaviour(self.parent,iData))
        self.subBehaviourChain.append(DetachBehaviour(self.parent,iData))
        
class DetachBehaviour(Behaviour):
    def __init__(self,iParent,iData):
        
        super(DetachBehaviour,self).__init__(iParent,iData)
        self.desc="Simple Detach behaviour"
        
    def start(self,result):
        
        cp=self.parent.getComponentByID(self.parent.TOW_COMPONENT_ID)
        if cp:
            self.result=cp.detach()
        
        self.finished=True
        
    
        
class AttachBehaviour(Behaviour):
    def __init__(self,iParent,iData):
        
        super(AttachBehaviour,self).__init__(iParent,iData)
        self.desc="Simple Attach behaviour"
        
    def start(self,result):
        super(AttachBehaviour,self).start(result)
        
        
        if not result:
            self.finished=True
            return
        
        self.finished=True
        
        if self.data:
            
            self.target=self.data['Target']
            if self.target:
                cp=self.parent.getComponentByID(BaseActor.TOW_COMPONENT_ID)
                if cp:
                    self.result=cp.attach(self.target)
                else : 
                    self.fail("NO Tow!")

        else:
            self.fail("NO DATA !!!")
                
        self.finished=True
             
        
   
    

class Iceberg(object):
    def __init__(self,iWorld,iName,iPoints):
        
        self.world=iWorld

        self.ic=iceberg.Iceberg2D(iName,iPoints,1.0)
        
        radius=0.
        ## radius calculation
        for pt in iPoints:
            x,y=pt
            r=(x*x+y*y)
            if r>radius:
                radius=r
        self.radius=math.sqrt(radius)
        
        self.name="Iceberg"
        triangles=self.ic.get_triangles()
        
        self.isSelectable=False
        
        bd=box2d.b2BodyDef() 
        bd.userData=self
        x,y=self.ic.center
        
        bd.position.Set(x,y)
        bd.allowSleep = True
        bd.isSleeping = True
        
        self.body = self.world.CreateBody(bd)
        
        
        #self.initShape(iPoints)
        
        for tri in triangles:
            
            sd=box2d.b2PolygonDef()
            sd.setVertices_tuple( tri )
            try:
                self.body.CreateShape(sd)
            except :
                pass
        
        self.extraDamage=10
    
    def initShape(self,iPoints):
        ### Not used, actors fall through :
        f=1.
        loop=[(a[0]*f,a[1]*f) for a in iPoints][0:10]
        print loop
        edgeDef = box2d.b2EdgeChainDef()
        edgeDef.setVertices(iPoints)
        edgeDef.isALoop = True
        self.body.CreateShape(edgeDef)    
    def getPosition(self,asTuple):
        if asTuple:
            return self.body.GetPosition().tuple()
        return self.body.GetPosition()
    
    def applyDamage(self,x):
        pass
        
     

class grStencil (pyglet.graphics.Group):
    """
    This pyglet rendering group enables Stencil Shadows
    """
        
    def set_state(self):
        ## write a one to the stencil buffer everywhere we are about to draw
        gl.glStencilFunc(gl.GL_ALWAYS, 1, 0xFFFFFFFF)
        ## this is to always pass a one to the stencil buffer where we draw
        gl.glStencilOp(gl.GL_REPLACE, gl.GL_REPLACE, gl.GL_REPLACE)

        ## render the plane which the shadow will be on
        ## color and depth buffer are disabled, only the stencil buffer
        ## will be modified
        color =  box2d.b2Color(1.0,1.0,1.0)
        
        
        

    def unset_state(self):
        ## turn the color and depth buffers back on
        gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE)
        gl.glDepthMask(gl.GL_TRUE)


        ## until stencil test is diabled, only write to areas where the
        ## stencil buffer has a one. This is to draw the shadow only on
        ## the floor.
        gl.glStencilFunc(gl.GL_EQUAL, 0, 0xFFFFFFFF)

        ## don't modify the contents of the stencil buffer
        gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_KEEP)
        ## end step 1
        

##class grRadar(pyglet.graphics.Group):
##    def set_state(self):
##        gl.glPushAttrib(gl.GL_COLOR_BUFFER_BIT | gl.GL_STENCIL_BUFFER_BIT | gl.GL_ENABLE_BIT)
##    
##        gl.glClearStencil(0)
##        gl.glClear(gl.GL_STENCIL_BUFFER_BIT)
##
##        ## step 1
##        ## turning off writing to the color buffer and depth buffer so we only 
##        ## write to stencil buffer
##        gl.glColorMask(0,0,0,0)
##        gl.glDepthMask(0)
##
##        ## enable stencil buffer
##        gl.glEnable(gl.GL_STENCIL_TEST)
##        
##    def unset_state(self):
##        gl.glDisable(gl.GL_STENCIL_TEST)
##        gl.glPopAttrib()
##        

            

class xenContactPoint:
    """
    Structure holding the necessary information for a contact point.
    All of the information is copied from the contact listener callbacks.
    """
    shape1 = None
    shape2 = None
    normal = None
    position = None
    velocity = None
    id  = box2d.b2ContactID()
    state = 0
    force=0
    
class fwContactTypes:
    """
    Acts as an enum, holding the types necessary for contacts:
    Added, persisted, and removed
    """
    contactUnknown = 0
    contactAdded = 1
    contactPersisted = 2
    contactRemoved = 3

class fwContactPoint:
    """
    Structure holding the necessary information for a contact point.
    All of the information is copied from the contact listener callbacks.
    """
    shape1 = None
    shape2 = None
    normal = None
    position = None
    velocity = None
    id  = box2d.b2ContactID()
    
    
class xenContactListener(box2d.b2ContactListener):
    """
    Handles all of the contact states passed in from Box2D.

    """
    test = None
    def __init__(self):
        super(xenContactListener, self).__init__()
        self.contactPool=[]
        

    def reset(self):
        self.contactPool[:]=[]
        self.contactFlag=False
##    def handleCall(self, state, point):
##        
##        k_maxContactPoints = 2048
##        if len(self.contactPool) == k_maxContactPoints: return
##        self.contactFlag=True
##        self.contactPool.append( fwContactPoint() )
##        cp = self.contactPool[-1]
##        cp.actors = (point.shape1.GetBody().GetUserData(),point.shape2.GetBody().GetUserData())
##        cp.id = point.id
##        cp.state = state
        
    def getCollisionEffects(self):
        l={}
        for cp in self.contactPool:
            a,b=cp.actors
            if not a in l:
                l[a]=10
            if not b in l:
                l[b]=10
            l[a]+=b.extraDamage
            l[b]+=a.extraDamage
        
        return l
            
    def Add(self, point):
        k_maxContactPoints = 2048
        if len(self.contactPool) == k_maxContactPoints: return
        self.contactFlag=True
        self.contactPool.append( fwContactPoint() )
        cp = self.contactPool[-1]
        cp.actors = (point.shape1.GetBody().GetUserData(),point.shape2.GetBody().GetUserData())
        cp.id = point.id
        

from gamestate import *


class Main (pyglet.window.Window):
    name="Xenocide"
    
    # Box2D-callbacks
    destructionListener = None
    boundaryListener = None
    contactListener = None
    debugDraw = None

    # Window-related
    fontname = "saved_by_zero"
    fontsize = 10
    font = None
    textGroup = None
    keys=pyglet.window.key.KeyStateHandler()
    
    def __init__(self):
        config=gl.Config(stencil_size=8)
    
        super(Main, self).__init__(config=config,height=800,width=1024, resizable=True)
        
        self.screenSize =(self.width, self.height)
        # Initialize the text display group
        self.textGroup = grText(self)

        # Load the font and record the screen dimensions
        self.font = pyglet.font.load(self.fontname, self.fontsize)
        
        pyglet.resource.path=['','res']
        pyglet.resource.reindex()
        pyglet.resource.add_font('saved_by_zero.ttf')
        
        self.gsStack=[]

        self.settings=xenSettings()

        self.currentGameState=MainMenu("menu","XENOCIDE",self,"Saved By Zero")
        self.currentGameState.activate()
                       
    def run(self):
        """
        Main loop.
        """
        
        pyglet.clock.schedule_interval(self.SimulationLoop, 1.0 / self.settings.hz)
        pyglet.clock.set_fps_limit(1.0 / self.settings.hz)
        pyglet.app.run()

    def SimulationLoop(self, dt):
        """
        The main simulation loop. Don't override this, override Step instead.
        And be sure to call super(classname, self).Step(settings) at the end
        of your Step function.
        """

        
        # Clear the screen
        self.clear()
        
        # Update the keyboard status
        self.push_handlers(self.keys)

        # Reset the text position
        #self.SetTextLine(30)
        gs=self.currentGameState
        gs.step(dt)
        gs.draw(dt)
        
        
        self.invalid = True
        
        

        
    def switchGameState(self,iGS):
        self.gsStack.append(self.currentGameState)
        self.currentGameState.deActivate()
        self.currentGameState=iGS
        self.currentGameState.activate()
        
        
    def popGS(self):
        self.currentGameState.deActivate()
        if len(self.gsStack)>0:
            self.currentGameState=self.gsStack.pop()
            self.currentGameState.activate()
        else :
            sys.exit()

if __name__=="__main__":
    test = Main()
    test.run()
    
    #test()
             
